package com.template.utils.redis;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Range;
import org.springframework.data.redis.connection.Limit;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Component;

import java.time.Duration;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Component
public class ZSetOps extends KeyOps {

    private final ZSetOperations<String, Object> zSetOperations;

    @Autowired
    public ZSetOps(RedisTemplate<String, Object> redisTemplate) {
        super(redisTemplate);
        this.zSetOperations = redisTemplate.opsForZSet();
    }

    /**
     * <h4> Sort Set </h4>
     * 添加元素
     * <li> zadd _key _score _value </li>
     */
    public Boolean zAdd(String key, double score, Object value) {
        return zSetOperations.add(key, value, score);
    }

    /**
     * <h4> Sort Set </h4>
     * 添加元素，若元素存在则保留旧元素
     * <li> zaddnx _key _score _value </li>
     */
    public Boolean zAddNx(String key, double score, Object value) {
        return zSetOperations.addIfAbsent(key, value, score);
    }

    /**
     * <h4> Sort Set </h4>
     * 添加元素
     * <li> zadd _key _score1 _value1 _score2 _value2 ... </li>
     */
    public Long zAdd(String key, Set<ZSetOperations.TypedTuple<Object>> values) {
        return zSetOperations.add(key, values);
    }

    /**
     * <h4> Sort Set </h4>
     * 添加元素，若元素存在则保留旧元素
     * <li> zaddnx _key _score1 _value1 _score2 _value2 ... </li>
     */
    public Long zAddNx(String key, Set<ZSetOperations.TypedTuple<Object>> values) {
        return zSetOperations.addIfAbsent(key, values);
    }

    /**
     * <h4> Sort Set </h4>
     * 删除元素
     * <li> zrem _key _value1 _value2 ... </li>
     */
    public Long zRem(String key, Object... values) {
        return zSetOperations.remove(key, values);
    }

    /**
     * <h4> Sort Set </h4>
     * 删除元素
     * <li> zrem _key _value1 _value2 ... </li>
     */
    public Long zRem(String key, Collection<Object> values) {
        return zSetOperations.remove(key, values.toArray());
    }

    /**
     * <h4> Sort Set </h4>
     * 获取元素个数
     * <li> zcard _key </li>
     */
    public Long zCard(String key) {
        return zSetOperations.zCard(key);
    }

    /**
     * <h4> Sort Set </h4>
     * 获取指定分数区间的元素个数
     * <li> zcount _key _min _max </li>
     */
    public Long zCount(String key, double min, double max) {
        return zSetOperations.count(key, min, max);
    }

    /**
     * <h4> Sort Set </h4>
     * 获取指定元素之间的元素个数
     * <li> zlexcount _key [_value1 [_value2 </li>
     */
    public Long zLexCount(String key, Range<String> range) {
        return zSetOperations.lexCount(key, range);
    }

    /**
     * <h4> Sort Set </h4>
     * 获取所有元素元素
     * <li> zrange _key 0 -1 </li>
     */
    public Set<Object> zRange(String key) {
        return zRange(key, false);
    }

    /**
     * <h4> Sort Set </h4>
     * 获取所有元素元素
     * <li> zrange _key 0 -1 </li>
     */
    public Set<Object> zRange(String key, boolean rev) {
        return zRange(key, 0, -1, rev);
    }

    /**
     * <h4> Sort Set </h4>
     * 获取指定排名之间的元素
     * <li> zrange _key _start _end </li>
     */
    public Set<Object> zRange(String key, long start, long end) {
        return zRange(key, start, end, false);
    }

    /**
     * <h4> Sort Set </h4>
     * 获取指定排名之间的元素
     * <li> zrange _key _start _end </li>
     */
    public Set<Object> zRange(String key, long start, long end, boolean rev) {
        return rev ? zSetOperations.reverseRange(key, start, end) : zSetOperations.range(key, start, end);
    }

    /**
     * <h4> Sort Set </h4>
     * 获取指定排名之间的元素与其分数
     * <li> zrange _key 0 -1 withscores </li>
     */
    public Set<ZSetOperations.TypedTuple<Object>> zRangeWithScores(String key) {
        return zSetOperations.rangeWithScores(key, 0, -1);
    }

    /**
     * <h4> Sort Set </h4>
     * 获取前数个排名的元素与其分数
     * <li> zrange _key 0 _rank withscores </li>
     */
    public Set<ZSetOperations.TypedTuple<Object>> zRangeWithScores(String key, long count) {
        if (count <= 0) return new HashSet<>();
        return zSetOperations.rangeWithScores(key, 0, count - 1);
    }

    /**
     * <h4> Sort Set </h4>
     * 获取指定排名之间的元素与其分数
     * <li> zrange _key _start _end withscores </li>
     */
    public Set<ZSetOperations.TypedTuple<Object>> zRangeWithScores(String key, long start, long end) {
        return zSetOperations.rangeWithScores(key, start, end);
    }

    /**
     * <h4> Sort Set </h4>
     * 获取指定排名之间的元素与其分数
     * <li> zrange _key 0 -1 withscores </li>
     */
    public Set<ZSetOperations.TypedTuple<Object>> zRevRangeWithScores(String key) {
        return zSetOperations.reverseRangeWithScores(key, 0, -1);
    }

    /**
     * <h4> Sort Set </h4>
     * 获取前数个排名的元素与其分数
     * <li> zrange _key 0 _rank withscores </li>
     */
    public Set<ZSetOperations.TypedTuple<Object>> zRevRangeWithScores(String key, long count) {
        if (count <= 0) return new HashSet<>();
        return zSetOperations.reverseRangeWithScores(key, 0, count - 1);
    }

    /**
     * <h4> Sort Set </h4>
     * 获取指定排名之间的元素与其分数
     * <li> zrange _key _start _end withscores </li>
     */
    public Set<ZSetOperations.TypedTuple<Object>> zRevRangeWithScores(String key, long start, long end) {
        return zSetOperations.reverseRangeWithScores(key, start, end);
    }

    /**
     * <h4> Sort Set </h4>
     * 获取指定分数之间的元素
     * <li> zrange _key _min _max byscore </li>
     */
    public Set<Object> zRangeByScore(String key, double min, double max) {
        return zSetOperations.rangeByScore(key, min, max);
    }

    /**
     * <h4> Sort Set </h4>
     * 获取指定分数之间的元素与其分数
     * <li> zrange _key _min _max byscore withscores </li>
     */
    public Set<ZSetOperations.TypedTuple<Object>> zRangeByScoreWithScores(String key, double min, double max) {
        return zSetOperations.rangeByScoreWithScores(key, min, max);
    }

    /**
     * <h4> Sort Set </h4>
     * 获取指定分数之间的元素与其分数，并对结果进行过滤
     * <li> zrange _key _min _max byscore limit _offset _count withscores </li>
     *
     * @param offset 从第几个开始过滤
     * @param count  offset之后的个数
     */
    public Set<ZSetOperations.TypedTuple<Object>> zRangeByScoreWithScores(String key, double min, double max, long offset, long count) {
        return zSetOperations.rangeByScoreWithScores(key, min, max, offset, count);
    }

    /**
     * <h4> Sort Set </h4>
     * 获取指定分数之间的元素
     * <li> zrange _key _min _max byscore </li>
     */
    public Set<Object> zRangeByLex(String key, Range<String> range) {
        return zSetOperations.rangeByLex(key, range);
    }

    /**
     * <h4> Sort Set </h4>
     * 获取指定分数之间的元素与其分数
     * <li> zrange _key _value1 _value2 bylex limit _offset _count </li>
     */
    public Set<Object> zRangeByLex(String key, Range<String> range, Limit limit) {
        return zSetOperations.rangeByLex(key, range, limit);
    }

    /**
     * <h4> Sort Set </h4>
     * 获取指定分数之间的元素与其分数
     * <li> zrange _key _value1 _value2 bylex limit _offset _count </li>
     */
    public Set<Object> zRangeByLex(String key, Range<String> range, int offset, int count) {
        return zSetOperations.rangeByLex(key, range, Limit.limit().offset(offset).count(count));
    }

    /**
     * <h4> Sort Set </h4>
     * 获取指定元素的分数
     * <li> zscore _key _value </li>
     */
    public Double zScore(String key, Object value) {
        return zSetOperations.score(key, value);
    }

    /**
     * <h4> Sort Set </h4>
     * 批量获取指定元素的分数
     * <li> zscore _key _value1 _value2 ... </li>
     */
    public List<Double> zScore(String key, Object... values) {
        return zSetOperations.score(key, values);
    }

    /**
     * <h4> Sort Set </h4>
     * 批量获取指定元素的分数
     * <li> zscore _key _value1 _value2 ... </li>
     */
    public List<Double> zScore(String key, Collection<Object> values) {
        return zSetOperations.score(key, values.toArray());
    }

    /**
     * <h4> Sort Set </h4>
     * 弹出分数最高的一位，并删除
     * <li> zpopmax _key </li>
     */
    public ZSetOperations.TypedTuple<Object> zPopMax(String key) {
        return zSetOperations.popMax(key);
    }

    /**
     * <h4> Sort Set </h4>
     * 依次弹出 count 个分数最高位，并删除
     * <li> zpopmax _key _count </li>
     */
    public Set<ZSetOperations.TypedTuple<Object>> zPopMax(String key, long count) {
        return zSetOperations.popMax(key, count);
    }

    /**
     * <h4> Sort Set </h4>
     * 弹出分数最低的一位，并删除
     * <li> zpopmin _key </li>
     */
    public ZSetOperations.TypedTuple<Object> zPopMin(String key) {
        return zSetOperations.popMin(key);
    }

    /**
     * <h4> Sort Set </h4>
     * 依次弹出 count 个分数最低位，并删除
     * <li> zpopmin _key _count </li>
     */
    public Set<ZSetOperations.TypedTuple<Object>> zPopMin(String key, long count) {
        return zSetOperations.popMin(key, count);
    }

    /**
     * <h4> Sort Set </h4>
     * 依次弹出 count 个分数最高位，并删除，若不存在则阻塞并等待元素插入
     * <li> bzpopmin _key _timeout </li>
     */
    public ZSetOperations.TypedTuple<Object> bZPopMax(String key, Duration timeout) {
        return zSetOperations.popMax(key, timeout);
    }

    /**
     * <h4> Sort Set </h4>
     * 依次弹出 count 个分数最低位，并删除，若不存在则阻塞并等待元素插入
     * <li> bzpopmin _key _timeout </li>
     */
    public ZSetOperations.TypedTuple<Object> bZPopMin(String key, Duration timeout) {
        return zSetOperations.popMin(key, timeout);
    }

    /**
     * <h4> Sort Set </h4>
     * 更改分数
     * <li> zincrby _key _value _score </li>
     */
    public Double zIncrBy(String key, Object value, double score) {
        return zSetOperations.incrementScore(key, value, score);
    }

}
